package rht

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"mime"
	"net/http"
	"os"
	"strings"
)

func NewHttpServerResponse(w http.ResponseWriter) HttpServerResponseFunc {
	return &httpServerResponseFunc{w: w, statusCode: http.StatusOK}
}

var _ HttpServerResponseFunc = new(httpServerResponseFunc)

type HttpServerResponseFunc interface {
	http.ResponseWriter
	ResponseWriter() http.ResponseWriter

	StatusCode() int

	// HeaderSet 设置响应头
	HeaderSet(key, value string)
	// HeaderAdd 添加响应头
	HeaderAdd(key, value string)
	// HeaderDel 删除响应头
	HeaderDel(key string)
	// HeaderConnectionClose 设置响应头 Connection: close
	HeaderConnectionClose()
	// HeaderConnectionKeepAlive 设置响应头 Connection: keep-alive
	HeaderConnectionKeepAlive()
	// HeaderSetContentType 设置响应头 Content-Type
	HeaderSetContentType(value string)
	// WriteStatusCode 写入状态码
	WriteStatusCode(statusCode int)

	// WriteHTML 写入响应体
	WriteHTML(statusCode int, str string) error
	// WriteString 写入响应体。
	WriteString(statusCode int, str string) error
	// WriteBytes 写入响应体。
	WriteBytes(statusCode int, contentType string, body []byte) error
	// WriteStream 写入响应体
	WriteStream(statusCode int, contentType string, reader io.Reader) error
	// WriteFile 写入响应体
	WriteFile(filePath string, req *http.Request) error
	// WriteFileStream 写入响应体
	WriteFileStream(reader io.Reader, ext string) error
	// WriteDownload 写入响应体，让前端下载。
	WriteDownload(name string, filePath string, req *http.Request) error
	// WriteDownloadStream 写入响应体，让前端下载。
	WriteDownloadStream(name string, reader io.Reader) error

	// WriteStdJSON 写入响应体，以JSON编码的格式，按 StdResp 结构体来编码。
	WriteStdJSON(code int, msg string, data any, other any) error
	// WriteStdJsonData 写入响应体，以JSON编码的格式，按 StdResp 结构体来编码。
	WriteStdJsonData(data any) error
	// WriteStdJsonDataOther 写入响应体，以JSON编码的格式，按 StdResp 结构体来编码。
	WriteStdJsonDataOther(data any, other any) error
	// WriteJSON 写入响应体，以JSON编码的格式。
	WriteJSON(v any) error
	// WriteJSONBytes 写入响应体，以JSON编码的格式。
	WriteJSONBytes(body []byte) error
	// WriteStdXML 写入响应体，以XML编码的格式，按 StdResp 结构体来编码。
	WriteStdXML(code int, msg string, data any, other any) error
	// WriteXML 写入响应体，以XML编码的格式。
	WriteXML(v any) error
	// WriteXMLBytes 写入响应体，以XML编码的格式。
	WriteXMLBytes(body []byte) error
}

type httpServerResponseFunc struct {
	w          http.ResponseWriter
	statusCode int
}

func (w *httpServerResponseFunc) ResponseWriter() http.ResponseWriter {
	return w.w
}

func (w *httpServerResponseFunc) Header() http.Header {
	return w.w.Header()
}
func (w *httpServerResponseFunc) Write(bytes []byte) (int, error) {
	return w.w.Write(bytes)
}

func (w *httpServerResponseFunc) WriteHeader(statusCode int) {
	w.statusCode = statusCode
	w.w.WriteHeader(statusCode)
}

func (w *httpServerResponseFunc) StatusCode() int {
	return w.statusCode
}

func (w *httpServerResponseFunc) HeaderSet(key, value string) {
	w.w.Header().Set(http.CanonicalHeaderKey(key), value)
}

func (w *httpServerResponseFunc) HeaderAdd(key, value string) {
	w.w.Header().Add(http.CanonicalHeaderKey(key), value)
}
func (w *httpServerResponseFunc) HeaderDel(key string) {
	w.w.Header().Del(http.CanonicalHeaderKey(key))
}

func (w *httpServerResponseFunc) HeaderConnectionClose() {
	w.w.Header().Set(headerConnection, "close")
}

func (w *httpServerResponseFunc) HeaderConnectionKeepAlive() {
	w.w.Header().Set(headerConnection, "keep-alive")
}

func (w *httpServerResponseFunc) HeaderSetContentType(value string) {
	w.w.Header().Set(headerContentType, value)
}

func (w *httpServerResponseFunc) WriteStatusCode(statusCode int) {
	w.WriteHeader(statusCode)
}

func (w *httpServerResponseFunc) WriteHTML(statusCode int, str string) error {
	w.WriteHeader(statusCode)
	w.w.Header().Set(headerContentType, headerContentTypeHTML)
	_, err := w.Write([]byte(str))
	return err
}

func (w *httpServerResponseFunc) WriteString(statusCode int, str string) error {
	w.WriteHeader(statusCode)
	w.w.Header().Set(headerContentType, headerContentTypeTextPlain)
	_, err := w.Write([]byte(str))
	return err
}

func (w *httpServerResponseFunc) WriteBytes(statusCode int, contentType string, body []byte) error {
	w.WriteHeader(statusCode)
	w.w.Header().Set(headerContentType, contentType)
	_, err := w.Write(body)
	return err
}

func (w *httpServerResponseFunc) WriteStream(statusCode int, contentType string, reader io.Reader) error {
	w.WriteHeader(statusCode)
	w.w.Header().Set(headerContentType, contentType)
	_, err := io.Copy(w, reader)
	return err
}

func (w *httpServerResponseFunc) WriteFile(filePath string, req *http.Request) error {
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	if err != nil {
		return err
	}
	http.ServeContent(w.w, req, fileInfo.Name(), fileInfo.ModTime(), file)
	return nil
}

func (w *httpServerResponseFunc) WriteFileStream(reader io.Reader, ext string) error {
	w.HeaderSet("Content-Type", mime.TypeByExtension(ext))
	_, err := io.Copy(w.ResponseWriter(), reader)
	return err
}

var dName = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")

func (w *httpServerResponseFunc) WriteDownload(name string, filePath string, req *http.Request) error {
	w.w.Header().Set(headerContentDisposition, fmt.Sprintf("%v; filename=%v", "attachment", dName.Replace(name)))
	return w.WriteFile(filePath, req)
}

func (w *httpServerResponseFunc) WriteDownloadStream(name string, reader io.Reader) error {
	w.w.Header().Set(headerContentDisposition, fmt.Sprintf("%v; filename=%v", "attachment", dName.Replace(name)))
	_, err := io.Copy(w, reader)
	return err
}

func (w *httpServerResponseFunc) WriteStdJSON(code int, msg string, data any, other any) error {
	var _stdResp = Resp{
		Code: code,
		Msg:  msg,
		Data: RespData{
			Data:  data,
			Other: other,
		},
	}
	marshal, err := json.Marshal(_stdResp)
	if err != nil {
		return err
	}
	w.w.Header().Set(headerContentType, headerContentTypeJson)
	_, err = w.Write(marshal)
	return err
}

func (w *httpServerResponseFunc) WriteStdJsonData(data any) error {
	return w.WriteStdJSON(http.StatusOK, "", data, nil)
}

func (w *httpServerResponseFunc) WriteStdJsonDataOther(data any, other any) error {
	return w.WriteStdJSON(http.StatusOK, "", data, other)
}

func (w *httpServerResponseFunc) WriteJSON(v any) error {
	marshal, err := json.Marshal(v)
	if err != nil {
		return err
	}
	w.w.Header().Set(headerContentType, headerContentTypeJson)
	_, err = w.Write(marshal)
	return err
}

func (w *httpServerResponseFunc) WriteJSONBytes(body []byte) error {
	w.w.Header().Set(headerContentType, headerContentTypeJson)
	_, err := w.Write(body)
	return err
}

func (w *httpServerResponseFunc) WriteStdXML(code int, msg string, data any, other any) error {
	var _stdResp = Resp{
		Code: code,
		Msg:  msg,
		Data: RespData{
			Data:  data,
			Other: other,
		},
	}
	marshal, err := xml.Marshal(_stdResp)
	if err != nil {
		return err
	}
	w.w.Header().Set(headerContentType, headerContentTypeXml)
	_, err = w.Write(marshal)
	return err
}

func (w *httpServerResponseFunc) WriteXML(v any) error {
	marshal, err := xml.Marshal(v)
	if err != nil {
		return err
	}
	w.w.Header().Set(headerContentType, headerContentTypeXml)
	_, err = w.Write(marshal)
	return err
}

func (w *httpServerResponseFunc) WriteXMLBytes(body []byte) error {
	w.w.Header().Set(headerContentType, headerContentTypeXml)
	_, err := w.Write(body)
	return err
}
